<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="bVGJS" id="bVGJS"><span data-lake-id="u8eb81643" id="u8eb81643">典型回答</span></h1>
  <p data-lake-id="ua1ab56fe" id="ua1ab56fe"><span data-lake-id="u052b42a9" id="u052b42a9" class="lake-fontsize-11" style="color: rgb(51, 51, 51)">Mybatis的缓存机制有两种：一级缓存和二级缓存。</span><span data-lake-id="u5ab58c01" id="u5ab58c01" class="lake-fontsize-11">Mybatis缓存的整体工作原理可以参考这篇文章</span></p>
  <p data-lake-id="u64403bc5" id="u64403bc5"><span data-lake-id="uabe6cc77" id="uabe6cc77" class="lake-fontsize-11">​</span><br></p>
  <h2 data-lake-id="eepR9" id="eepR9"><span data-lake-id="u1e798d82" id="u1e798d82">一级缓存</span></h2>
  <p data-lake-id="u12b258bf" id="u12b258bf"><span data-lake-id="uf0919592" id="uf0919592" style="color: rgb(51, 51, 51)">在同一个会话中，Mybatis会将执行过的SQL语句的结果缓存到内存中，下次再执行相同的SQL语句时，会先查看缓存中是否存在该结果，如果存在则直接返回缓存中的结果，不再执行SQL语句。一级缓存是默认开启的，可以通过在Mybatis的配置文件中设置禁用或刷新缓存来控制缓存的使用。</span></p>
  <p data-lake-id="u113528e4" id="u113528e4"><span data-lake-id="u93f7554a" id="u93f7554a" style="color: rgb(51, 51, 51)">工作流程如下：</span></p>
  <p data-lake-id="u4d01884d" id="u4d01884d"><img src="https://cdn.nlark.com/yuque/0/2023/png/719664/1684769065876-bd895685-02d1-493b-acdc-4e9386200dbf.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_45%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u4b21da81" id="u4b21da81"><span data-lake-id="u38c894e2" id="u38c894e2" style="color: rgb(51, 51, 51)">对于一级缓存，有两点需要注意的是：</span></p>
  <ol list="u4d8aed87">
   <li fid="u2a5cda4c" data-lake-id="ud844b1ba" id="ud844b1ba"><span data-lake-id="u2874af58" id="u2874af58">MyBatis一级缓存内部设计简单，只是一个没有容量限定的HashMap，在缓存的功能性上有所欠缺。</span></li>
   <li fid="u2a5cda4c" data-lake-id="ue6465b46" id="ue6465b46"><span data-lake-id="u77ee2e69" id="u77ee2e69">MyBatis的一级缓存最大范围是SqlSession内部，有多个SqlSession或者分布式的环境下，数据库写操作会引起脏数据，换句话说，当一个SqlSession查询并缓存结果后，另一个SqlSession更新了该数据，其他缓存结果的SqlSession是看不到更新后的数据的。所以建议设定缓存级别为Statement。</span></li>
  </ol>
  <h2 data-lake-id="ZK3Am" id="ZK3Am"><span data-lake-id="ud562e8af" id="ud562e8af">二级缓存</span></h2>
  <p data-lake-id="uaad77cfe" id="uaad77cfe"><span data-lake-id="u354a878c" id="u354a878c">二级缓存是基于命名空间的缓存，它可以跨会话，在多个会话之间共享缓存，可以减少数据库的访问次数。要使用二级缓存，需要在Mybatis的配置文件中配置相应的缓存实现类，并在需要使用缓存的Mapper接口上添加</span><code data-lake-id="udd2f5e75" id="udd2f5e75"><span data-lake-id="ub70d1ee6" id="ub70d1ee6">@CacheNamespace</span></code><span data-lake-id="u16c6a7d7" id="u16c6a7d7">注解。二级缓存的使用需要注意缓存的更新和失效机制，以及并发操作的问题。</span></p>
  <p data-lake-id="udeb7aeb6" id="udeb7aeb6"><span data-lake-id="u395828e5" id="u395828e5">工作流程如下：</span></p>
  <p data-lake-id="u7e30cfce" id="u7e30cfce"><img src="https://cdn.nlark.com/yuque/0/2023/png/719664/1684769046065-3aaaa9c9-0d33-4093-9ec5-1094968c4b2c.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_28%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u0886195e" id="u0886195e"><span data-lake-id="u781d347e" id="u781d347e">因为二级缓存是基于namespace的，所以一般情况下，Mybatis的二级缓存是不适合多表查询的情况的。举个例子：</span></p>
  <p data-lake-id="u3fe6ff16" id="u3fe6ff16"><span data-lake-id="u3e19e450" id="u3e19e450">我们有两个表：student和class，我们为这两个表创建了两个namespace去对这两个表做相关的操作。同时，为了进行多表查询，我们在namespace=student的空间中，对student和class两张表进行了关联查询操作（sqlA）。此时就会在namespace=student的空间中把sqlA的结果缓存下来，如果我们在namespace=class下更新了class表，namespace=student是不会更新的，这就会导致脏数据的产生。</span></p>
 </body>
</html>